# -*- coding: utf-8 -*-
"""
@Time    : 2024/8/21 10:51 
@Author  : ZhangShenao 
@File    : 1.OpenAI原生工具调用.py 
@Desc    : 使用OpenAI原生API,实现工具调用

函数调用的执行流程:
1. 应用根据用户原始问题,构造Prompt,调用LLM
2. LLM从Prompt中识别出需要调用函数/工具,生成具体要调用的函数/工具列表,以及实际调用的参数
3. 应用接收到需要调用的函数和参数,在本地完成函数调用,获取返回结果
4. 应用将原始Prompt和函数调用结果,一并提交给LLM,由LLM生成最终结果

函数调用 = 预定义的Prompt + 支持函数调用的LLM + 函数/工具及参数列表 + 本地调用代码

函数调用的作用是:可以更可靠地从LLM中获取结构化响应数据

函数调用列表是通过额外的tools工具传递给LLM的,与Prompt是独立的

LLM本身的函数调用并不会调用我们预定义的函数,而仅仅是生成我们需要调用的函数的调用参数而已
具体调用函数的动作,需要在我们自己的应用本地完成
"""
import os

import dotenv
from openai import OpenAI

# 加载环境变量
dotenv.load_dotenv()

# 创建OpenAI客户端
client = OpenAI(base_url=os.getenv("OPENAI_API_BASE"))

# 定义需要调用的工具列表
tools = [
    {
        "type": "function",  # 函数调用
        "function": {
            "name": "get_current_weather",  # 函数名
            "description": "Get the current weather in a given location",  # 函数描述
            "parameters": {  # 参数列表
                "type": "object",
                "properties": {
                    "location": {
                        "type": "string",
                        "description": "The city and state, e.g. San Francisco, CA",
                    },
                    "unit": {"type": "string", "enum": ["celsius", "fahrenheit"]},
                },
                "required": ["location"],  # 必须的参数
            },
        }
    }
]

# 定义原始Prompt
messages = [{"role": "user", "content": "What's the weather like in Boston today?"}]

# 调用OpenAI
completion = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages,
    tools=tools,  # 传入工具列表
    tool_choice="auto"  # 指定工具选择模式为auto,即由LLM自动识别是否需要调用工具
)

# 打印需要调用的函数即参数
print(completion.choices[0].message.tool_calls)
